home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgramD2.iso
/
Borland
/
Borland C++ V5.02
/
PVIEW95.PAK
/
PROCTHRD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-06
|
18KB
|
523 lines
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) 1993-1995 Microsoft Corporation. All Rights Reserved.
//
// MODULE: procthrd.c
//
// PURPOSE: Implements process and thread enumeration/manipulation
// functions.
//
// FUNCTIONS:
// InitToolhelp32 - Dynamically resolves addresses of 32-bit
// Toolhelp functions
// RefreshThreadList - Enumerates and displays active threads
// RefreshProcessList - Enumerates and displays active processes
// GetProcessModule - Gets information about a specific module in
// a specified process
// KillProcess - Kills the specified process
// GetModuleNameFromExe - Returns a Win16 app/DLL's module name from
// its executable file.
//
//
// COMMENTS:
//
#include <windows.h>
#include <tlhelp32.h> // Required for ToolHelp32 functions
#include <commctrl.h>
#include "procthrd.h"
#include "listview.h"
#include "globals.h"
//-------------------------------------------------------------------------
// Type definitions for functions pointers used to call 32-bit Toolhelp
// functions.
typedef BOOL (WINAPI *MODULEWALK)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
typedef BOOL (WINAPI *THREADWALK)(HANDLE hSnapshot, LPTHREADENTRY32 lpte);
typedef BOOL (WINAPI *PROCESSWALK)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
typedef HANDLE (WINAPI *CREATESNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);
//-------------------------------------------------------------------------
// File-scope globals. These pointers are declared because we have to
// dynamically link to these funtions. They are exported only by the
// Windows 95 KERNEL32.DLL. Explicitly linking to them will make this
// application unloadable on Windows NT and will produce an ugly system
// dialog that isn't nice for end-users to see.
static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
static MODULEWALK pModule32First = NULL;
static MODULEWALK pModule32Next = NULL;
static PROCESSWALK pProcess32First = NULL;
static PROCESSWALK pProcess32Next = NULL;
static THREADWALK pThread32First = NULL;
static THREADWALK pThread32Next = NULL;
//-------------------------------------------------------------------------
// Local function prototypes.
BOOL GetProcessModule (DWORD dwPID, DWORD dwModuleID, LPMODULEENTRY32 lpMe32,
DWORD cbMe32);
BOOL GetModuleNameFromExe (LPCSTR szFileName, LPSTR szModuleName, WORD cbLen);
//
// FUNCTION: InitToolhelp32(void)
//
// PURPOSE: Initializes pointers to the 32-bit Toolhelp APIs that are
// exported only by the Windows 95 KERNEL32.DLL.
//
// PARAMETERS:
// None.
//
// RETURN VALUE:
// TRUE if addresses of all needed 32-bit Toolhelp functions were
// retrieved.
// FALSE if we couldn't get the address of even one needed 32-bit
// Toolhelp function
//
// COMMENTS:
// This function is needed to initialize the function pointers to the
// 32-bit Toolhelp functions because at this time, only the Windows 95
// KERNEL32.DLL exports them. If we did not dynamically resolve the
// addresses of these functions, this application would not even load
// on anything but Windows 95.
//
// In the case of this sample, this function is called in InitApplication
// which will prevent this application from even running if it can't
// access the necessary functions.
//
BOOL InitToolhelp32 (void)
{
BOOL bRet;
HANDLE hKernel;
// Obtain a module handle to KERNEL so that we can get the addresses of
// the 32-bit Toolhelp functions we need.
hKernel = GetModuleHandle("KERNEL32.DLL");
if (hKernel)
{
pCreateToolhelp32Snapshot =
(CREATESNAPSHOT)GetProcAddress(hKernel, "CreateToolhelp32Snapshot");
pModule32First = (MODULEWALK)GetProcAddress(hKernel,
"Module32First");
pModule32Next = (MODULEWALK)GetProcAddress(hKernel,
"Module32Next");
pProcess32First = (PROCESSWALK)GetProcAddress(hKernel,
"Process32First");
pProcess32Next = (PROCESSWALK)GetProcAddress(hKernel,
"Process32Next");
pThread32First = (THREADWALK)GetProcAddress(hKernel,
"Thread32First");
pThread32Next = (THREADWALK)GetProcAddress(hKernel,
"Thread32Next");
// All of our addresses must be non-NULL in order for us to be
// successful. If even one of these addresses is NULL, then we
// must fail because we won't be able to walk one of the lists
// we need to.
bRet = pModule32First && pModule32Next && pProcess32First &&
pProcess32Next && pThread32First && pThread32Next &&
pCreateToolhelp32Snapshot;
}
else
bRet = FALSE; // Couldn't even get a module handle to KERNEL.
return bRet;
}
//
// FUNCTION: RefreshThreadList(HWND, DWORD)
//
// PURPOSE: Enumerates and displays the list of threads owned by a
// specified process.
//
// PARAMETERS:
// hListView - Handle of the listview that lists thread information
// dwOwnerPID - ID of process whose threads we will list
//
// RETURN VALUE:
// TRUE if the threads were successfully enumerated and listed
// FALSE if the threads could not be enumerated or listed
//
// COMMENTS:
//
BOOL RefreshThreadList (HWND hListView, DWORD dwOwnerPID)
{
HANDLE hThreadSnap;
BOOL bRet;
THREADENTRY32 te32 = {0};
// Take a snapshot of all threads currently in the system.
hThreadSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == (HANDLE)-1)
return (FALSE);
// Clear the current contents of the thread list view (which are now old).
ListView_DeleteAllItems(g_hwndThread);
// Size of the THREADENTRY32 structure must be filled out before use.
te32.dwSize = sizeof(THREADENTRY32);
// Walk thread snapshot to find all threads of the process we want.
// If the thread belongs to the process we want, add its information
// to the display list.
if (pThread32First(hThreadSnap, &te32))
{
do
{
if (te32.th32OwnerProcessID == dwOwnerPID)
{
TINFO ti;
ti.tid = te32.th32ThreadID;
ti.pidOwner = te32.th32OwnerProcessID;
ti.tpDeltaPri = te32.tpDeltaPri;
ti.tpBasePri = te32.tpBasePri;
AddThreadItem(hListView, ti);
}
}
while (pThread32Next(hThreadSnap, &te32));
bRet = TRUE;
}
else
bRet = FALSE; // Couldn't walk the list of threads.
// Don't forget to clean up the snapshot object...
CloseHandle (hThreadSnap);
return (bRet);
}
//
// FUNCTION: RefreshProcessList(HWND)
//
// PURPOSE: Enumerates and displays the list of processes.
//
// PARAMETERS:
// hListView - Handle of the listview that lists process information
//
// RETURN VALUE:
// TRUE if the processes were successfully enumerated and listed
// FALSE if the processes could not be enumerated or listed
//
// COMMENTS:
// Refreshes the list of processes by making a process snapshot and
// putting info about each process into the listview control specifed by
// hListView.
BOOL RefreshProcessList (HWND hListView)
{
HANDLE hProcessSnap;
BOOL bRet;
PROCESSENTRY32 pe32 = {0};
// Take a snapshot of all processes currently in the system.
hProcessSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == (HANDLE)-1)
return (FALSE);
// Clear the current contents of the process list view (which are now old).
ListView_DeleteAllItems(g_hwndProcess);
// Size of the PROCESSENTRY32 structure must be filled out before use.
pe32.dwSize = sizeof(PROCESSENTRY32);
// Walk the snapshot of processes and for each process, get information
// to display.
if (pProcess32First(hProcessSnap, &pe32))
{
BOOL bGotModule;
MODULEENTRY32 me32 = {0};
PINFO pi = {{0}, 0};
do
{
bGotModule = GetProcessModule(pe32.th32ProcessID,
pe32.th32ModuleID,
&me32,
sizeof(MODULEENTRY32));
if (bGotModule)
{
HANDLE hProcess;
// Get actual priority class
hProcess = OpenProcess (PROCESS_ALL_ACCESS,
FALSE,
pe32.th32ProcessID);
pi.dwPriorityClass = GetPriorityClass (hProcess);
CloseHandle (hProcess);
// Get process's base priority value
pi.pcPriClassBase = pe32.pcPriClassBase;
pi.pid = pe32.th32ProcessID;
pi.cntThreads = pe32.cntThreads;
lstrcpy(pi.szFullPath, pe32.szExeFile);
// Test to see if the app is a Win16 or Win32 app. If the
// file name returned in the PROCESSENTRY32 and MODULEENTRY32
// structures are equal, then we have a Win32 app, otherwise,
// we have a Win16 app.
if (!lstrcmpi (pe32.szExeFile, me32.szExePath))
{
// Win32 app, use MODULENETRY32 module name
lstrcpy(pi.szModName, me32.szModule);
pi.uAppType = EXETYPE_32BIT;
}
else
{
// Win16 app, get module name out of EXE header of file
if (!GetModuleNameFromExe (pe32.szExeFile, pi.szModName,
sizeof(pi.szModName)))
{
// If we can't get the module name for some reason, at
// least put something in the module name.
lstrcpy(pi.szModName, me32.szModule);
}
pi.uAppType = EXETYPE_16BIT;
}
AddProcessItem(hListView, pi);
}
}
while (pProcess32Next(hProcessSnap, &pe32));
bRet = TRUE;
}
else
bRet = FALSE; // Couldn't walk the list of processes.
// Don't forget to clean up the snapshot object...
CloseHandle (hProcessSnap);
return (bRet);
}
//
// FUNCTION: GetProcessModule(DWORD, DWORD, LPMODULEENTRY32, DWORD)
//
// PURPOSE: Given a Process ID and module ID, return its module information.
//
// PARAMETERS:
// dwPID - ID of process that owns the module we want information
// about.
// dwModuleID - ToolHelp32 ID of the module within the process
// lpMe32 - Structure to return data about the module we want
// cbMe32 - Size of the buffer pointed to by lpMe32--to make sure we
// don't copy too much data into lpMe32.
//
// RETURN VALUE:
// TRUE if it returns information about the specifed module.
// FALSE if it could not enumerate the modules in the process, or the
// module is not found in the process.
//
// COMMENTS:
//
BOOL GetProcessModule (DWORD dwPID,
DWORD dwModuleID,
LPMODULEENTRY32 lpMe32,
DWORD cbMe32)
{
BOOL bRet;
BOOL bFound = FALSE;
HANDLE hModuleSnap;
MODULEENTRY32 me32 = {0};
// Take a snapshot of all modules in the specified process.
hModuleSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
if (hModuleSnap == (HANDLE)-1)
return (FALSE);
// Size of the MODULEENTRY32 structure must be initialized before use!
me32.dwSize = sizeof(MODULEENTRY32);
// Walk the module list of the process and find the module we are
// interested in. Then, copy the information to the buffer pointed to
// by lpMe32 so that we can return it to the caller.
if (pModule32First(hModuleSnap, &me32))
{
do
{
if (me32.th32ModuleID == dwModuleID)
{
CopyMemory (lpMe32, &me32, cbMe32);
bFound = TRUE;
}
}
while (!bFound && pModule32Next(hModuleSnap, &me32));
bRet = bFound; // If this sets bRet to FALSE, then dwModuleID
// no longer exsists in the specified process.
}
else
bRet = FALSE; // Couldn't walk module list.
// Don't forget to clean up the snapshot object...
CloseHandle (hModuleSnap);
return (bRet);
}
//
// FUNCTION: KillProcess(DWORD)
//
// PURPOSE: To kills a specified process
//
// PARAMETERS:
// dwPID - Process ID of the process to kill
//
// RETURN VALUE:
// TRUE if the specified process was killed
// FALSE if it wasn't killed.
//
// COMMENTS:
// KillProcess does not return until the process is terminated.
//
BOOL KillProcess (DWORD dwPID)
{
BOOL bRet;
HANDLE hProcess;
// Open the process to obtain a handle to it. If we get a handle,
// try to terminate the process. Wait until the process is really
// dead before returning.
hProcess = OpenProcess (PROCESS_TERMINATE, FALSE, dwPID);
if (hProcess != NULL)
{
bRet = TerminateProcess (hProcess, 0xFFFFFFFF);
// Don't want to wait if the terminate fails. If the
// process is still running and we can't terminate it,
// then waiting for it would cause this process to stop
// execution.
if (bRet)
WaitForSingleObject(hProcess, INFINITE);
CloseHandle (hProcess);
}
else
bRet = FALSE;
return (bRet);
}
//
// FUNCTION: GetModuleNameFromExe(LPCSTR, LPSTR, WORD)
//
// PURPOSE: Retrieves the module name of a Win16 app or DLL from its
// excutable file.
//
// PARAMETERS:
// szFileName - Executable file (.EXE or .DLL) from which to retrieve
// module name
// szModuleName - Points to buffer that receives the module name
// cbLen - Specifies maximum length of szModuleName including NULL
//
// RETURN VALUE:
// TRUE if the module name was succesfully copied into szModuleName.
// FALSE if it wasn't killed.
//
// COMMENTS:
// Works for Win16 New Executable files only.
//
BOOL GetModuleNameFromExe (LPCSTR szFileName, LPSTR szModuleName, WORD cbLen)
{
BOOL bResult;
HANDLE hFile = NULL;
HANDLE hFileMapping = NULL;
PIMAGE_OS2_HEADER pNEHdr;
PIMAGE_DOS_HEADER pDosExeHdr = NULL;
// Open the file as read-only. (This file may be opened already by the
// system if it is an application or DLL that is currently loaded.)
// Create a read-only file mapping and map a read-only view of the file.
// If we can't open the file for some reason, then return FALSE.
hFile = CreateFile(szFileName,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hFileMapping == NULL)
{
CloseHandle(hFile);
return FALSE;
}
pDosExeHdr = (PIMAGE_DOS_HEADER)MapViewOfFile (hFileMapping,
FILE_MAP_READ,
0,
0,
0);
if (!pDosExeHdr)
{
CloseHandle(hFileMapping);
CloseHandle(hFile);
return FALSE;
}
__try
{
// Go to the beginning of the NE header.
pNEHdr =
(PIMAGE_OS2_HEADER)((LPSTR)pDosExeHdr + pDosExeHdr -> e_lfanew);
// Check to make sure that the file has DOS and NE EXE headers
if (pDosExeHdr -> e_magic == IMAGE_DOS_SIGNATURE
&& pNEHdr -> ne_magic == IMAGE_OS2_SIGNATURE)
{
lstrcpyn (szModuleName, (LPSTR)pNEHdr + pNEHdr -> ne_restab +1,
min((BYTE)*((LPSTR)pNEHdr + pNEHdr -> ne_restab) + 1,
cbLen));
bResult = TRUE;
}
else
bResult = FALSE;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
// If an access violation occurs in the try block, we know the file
// is not a NE file because it is too small to have a NE header, or
// the offset of the NE header isn't close to being correct.
bResult = FALSE;
}
// Clean up file mapping, all views of file mapping, and close the
// file.
UnmapViewOfFile(pDosExeHdr);
CloseHandle(hFileMapping);
CloseHandle(hFile);
return bResult;
}